import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * author: MaHX
 * date: 2019/9/18/16:44
 * description:
 * <p>
 * wait()会虚假唤醒，需要用while（）{ this.wait() }才行
 * <p>
 * 用同步锁不能用wait（）和notifyAll(),得用condition的await（）和signalAll()
 **/
public class TestProductorAndConsumer {
    public static void main(String args[]) {
        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);
        new Thread(producer, "生产者A").start();
        new Thread(producer, "生产者B").start();

        new Thread(consumer, "消费者A").start();
        new Thread(consumer, "消费者B").start();
    }

    /**
     * 店员
     */
    static class Clerk {
        private int product = 0;

        private Lock lock = new ReentrantLock();
        //通信线程
        private Condition condition = lock.newCondition();

        public synchronized void get() {
            while (product >= 1) {
                System.out.println(Thread.currentThread().getName() + " 货物已满");
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " 进货,现在货物有：" + ++product);
            this.notifyAll();

        }

        public void sale() {
            lock.lock();
            try {
                while (product <= 0) {
                    System.out.println(Thread.currentThread().getName() + " 货物不足");
                    try {
//                        this.wait();
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + " 买货,现在货物有：" + --product);
//                this.notifyAll();
                condition.signalAll();
            } finally {
                lock.unlock();
            }

        }
    }

    /**
     * 生产商
     */
    static class Producer implements Runnable {
        private Clerk clerk;

        public Producer(Clerk clerk) {
            this.clerk = clerk;
        }

        @Override
        public void run() {
            for (int i = 0; i < 40; i++) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clerk.get();
            }
        }
    }

    static class Consumer implements Runnable {
        private Clerk clerk;

        public Consumer(Clerk clerk) {
            this.clerk = clerk;
        }

        @Override
        public void run() {
            for (int i = 0; i < 40; i++) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clerk.sale();
            }
        }
    }
}
